package com.yangcangclub.pay.tenpay;

import com.google.common.collect.Maps;
import com.yangcangclub.commons.config.SysConfig;
import com.yangcangclub.commons.exception.ApolloException;
import com.yangcangclub.commons.result.MessageEnum;
import com.yangcangclub.commons.utils.StringUtil;
import com.yangcangclub.pay.utils.HttpUtils;
import com.yangcangclub.pay.utils.Identities;
import com.yangcangclub.pay.utils.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by chenbo on 2017/2/27.
 */
@Component
public class WeChatUtil {

    @Autowired
    SysConfig sysConfig;

    @Autowired
    Identities identities;

    private static Logger logger = LoggerFactory.getLogger(WeChatUtil.class);

    /** 微信统一下单
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
     * @param tradeNo
     * @param amount
     * @param subject
     * @param bodyInfo
     * @param openid
     * @param reqNo
     * @return
     * @throws Exception
     */
    public Map<String,String> getWeChatParameter(String tradeNo, String amount,
                                                 String subject, String bodyInfo,
                                                 String openid, String reqNo) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("attach", reqNo);
        paramMap.put("out_trade_no", tradeNo);
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("total_fee", String.valueOf(new BigDecimal(amount).multiply(new BigDecimal(100)).longValue()));//单位是分
        paramMap.put("nonce_str", identities.uuid2());
        paramMap.put("spbill_create_ip", "127.0.0.1");
        paramMap.put("notify_url", sysConfig.getYccBaseUrl()+sysConfig.getWechatNotifyUrl());
        paramMap.put("trade_type", sysConfig.getWechatTradeType());
        paramMap.put("openid", openid);
//        paramMap.put("body", java.net.URLEncoder.encode(bodyInfo,"utf-8"));
        paramMap.put("body", bodyInfo);
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号统一下单请求参数：" + xml);
        String result = HttpUtils.postXmlString(WeChatConfig.ORDER_URL, xml);
        logger.info("微信公众号统一下单返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        SortedMap<String, String> map = new TreeMap<String, String>();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            map.put("package", "prepay_id="+resultMap.get("prepay_id"));
            map.put("appId", resultMap.get("appid"));
            map.put("timeStamp", String.valueOf(new Date().getTime()));
            map.put("nonceStr", Identities.uuid2());
            map.put("signType", "MD5");
            sign = WeChatTool.wxSign(map, sysConfig.getWechatAppKey());
            map.put("paySign", sign);
            map.put("prepayId",resultMap.get("prepay_id"));
        }else{
            throw new ApolloException(MessageEnum.ERROR_WECHAT_SIGN_FAILURE);
        }
        return map;
    }

    /** 微信继续支付
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
     * @param prepayId
     * @return
     * @throws Exception
     */
    public Map<String,String> getWeChatParameter(String tradeNo,String prepayId) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("out_trade_no", tradeNo);
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("nonce_str", identities.uuid2());
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号 查询订单请求参数：" + xml);
        String result = HttpUtils.postXmlString(WeChatConfig.ORDERQUERY_URL, xml);
        logger.info("微信公众号 查询订单返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        SortedMap<String, String> map = new TreeMap<String, String>();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            if("NOTPAY".equals(resultMap.get("trade_state"))){
                map.put("package", "prepay_id="+prepayId);
                map.put("appId", sysConfig.getWechatWebAppId());
                map.put("timeStamp", String.valueOf(new Date().getTime()));
                map.put("nonceStr", Identities.uuid2());
                map.put("signType", "MD5");
                sign = WeChatTool.wxSign(map, sysConfig.getWechatAppKey());
                map.put("paySign", sign);
            }else{
                logger.info("ERROR_WECHAT_PAY_FAILURE>>>订单号:"+resultMap.get("out_trade_no")+"微信支付状态为:"+resultMap.get("trade_state"));
                throw new ApolloException(MessageEnum.ERROR_WECHAT_PAY_FAILURE);
            }
        }else{
            throw new ApolloException(MessageEnum.ERROR_WECHAT_SIGN_FAILURE);
        }
        return map;
    }

    /** 微信关闭订单
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
     * @param tradeNo
     * @return
     * @throws Exception
     */
    public Map<String,String> close(String tradeNo) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("out_trade_no", tradeNo);
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("nonce_str", identities.uuid2());
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号 关闭订单请求参数：" + xml);
        String result = HttpUtils.postXmlString(WeChatConfig.CLOSEORDER_URL, xml);
        logger.info("微信公众号 关闭订单返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        Map map = Maps.newHashMap();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            if("OK".equals(resultMap.get("result_msg"))){
                map.put("result",true);
            }
        }else{
            map.put("result",false);
            map.put("errorMsg","微信-订单交易关闭-订单号:"+tradeNo+
                    "RETURN_CODE:"+resultMap.get("return_code")+
                    "RETURN_MSG:"+resultMap.get("return_msg"));
            if("SUCCESS".equals(resultMap.get("return_code"))){
                map.put("errorMsg","微信-订单交易关闭-订单号:"+tradeNo+
                        "RETURN_CODE:"+resultMap.get("return_code")+
                        "RETURN_MSG:"+resultMap.get("return_msg")+
                        "ERR_CODE:"+resultMap.get("err_code")+
                        "ERR_CODE_DES:"+resultMap.get("err_code_des"));
            }
        }
        return map;
    }

    /**查询订单
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
     * @param tradeNo
     * @return
     * @throws Exception
     */
    public Map<String,String> tradeQuery(String tradeNo) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("out_trade_no", tradeNo);
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("nonce_str", identities.uuid2());
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号 查询订单请求参数：" + xml);
        String result = HttpUtils.postXmlString(WeChatConfig.ORDERQUERY_URL, xml);
        logger.info("微信公众号 查询订单返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        Map map = Maps.newHashMap();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            map.put("result",true);
            map.put("out_trade_no",resultMap.get("out_trade_no"));
            map.put("transaction_id",resultMap.get("transaction_id"));
            map.put("openid",resultMap.get("openid"));
            map.put("trade_state",resultMap.get("trade_state"));
            map.put("total_fee",resultMap.get("total_fee"));
            map.put("settlement_total_fee",resultMap.get("settlement_total_fee"));
            map.put("time_end",resultMap.get("time_end"));
//            map.put("trade_state_desc",resultMap.get("trade_state_desc"));
//            map.put("is_subscribe",resultMap.get("is_subscribe"));
//            map.put("trade_type",resultMap.get("trade_type"));
//            map.put("bank_type",resultMap.get("bank_type"));
        }else{
            map.put("result",false);
            map.put("errorMsg","微信-订单查询-订单号:"+tradeNo+
                    "RETURN_CODE:"+resultMap.get("return_code")+
                    "RETURN_MSG:"+resultMap.get("return_msg"));
            if("SUCCESS".equals(resultMap.get("return_code"))){
                map.put("errorMsg","微信-订单查询-订单号:"+tradeNo+
                        "RETURN_CODE:"+resultMap.get("return_code")+
                        "RETURN_MSG:"+resultMap.get("return_msg")+
                        "ERR_CODE:"+resultMap.get("err_code")+
                        "ERR_CODE_DES:"+resultMap.get("err_code_des"));
            }
        }
        return map;
    }

    /**查询退款
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
     * @param tradeNo
     * @return
     * @throws Exception
     */
    public Map<String,String> refundQuery(String tradeNo) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("nonce_str", identities.uuid2());
        paramMap.put("out_trade_no", tradeNo);
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号 查询退款请求参数：" + xml);
        String result = HttpUtils.postXmlString(WeChatConfig.REFUNDQUERY_URL, xml);
        logger.info("微信公众号 查询退款返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        Map map = Maps.newHashMap();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            map.put("result",true);
            map.put("out_trade_no",resultMap.get("out_trade_no"));
            map.put("transaction_id",resultMap.get("transaction_id"));
            map.put("total_fee",resultMap.get("total_fee"));
            if("1".equals(map.get("refund_count"))){
                map.put("out_refund_no",resultMap.get("out_refund_no"));
                map.put("refund_fee",resultMap.get("refund_fee"));
                map.put("refund_status",resultMap.get("refund_status"));
            }
        }else{
            map.put("result",false);
            map.put("errorMsg","微信-订单退款查询-订单号:"+tradeNo+
                    "RETURN_CODE:"+resultMap.get("return_code")+
                    "RETURN_MSG:"+resultMap.get("return_msg"));
            if("SUCCESS".equals(resultMap.get("return_code"))){
                map.put("errorMsg","微信-订单退款查询-订单号:"+tradeNo+
                        "RETURN_CODE:"+resultMap.get("return_code")+
                        "RETURN_MSG:"+resultMap.get("return_msg")+
                        "ERR_CODE:"+resultMap.get("err_code")+
                        "ERR_CODE_DES:"+resultMap.get("err_code_des"));
            }
        }
        return map;
    }

    /** 退款
     * @param tradeNo   订单号
     * @param outRefundNo   唯一退款订单号
     * @param refundAccount  退款资金来源 REFUND_SOURCE_UNSETTLED_FUNDS（默认）---未结算资金退款（默认使用未结算资金退款）
    REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款(限非当日交易订单的退款）
     * @param realPrice
     * @param refundPrice
     * @return
     * @throws Exception
     */
    public Map<String,String> refund(String tradeNo,String outRefundNo,String refundAccount,
                                     String realPrice,String refundPrice) throws Exception {
        SortedMap<String,String> paramMap = new TreeMap<>();
        paramMap.put("appid", sysConfig.getWechatWebAppId());
        paramMap.put("mch_id", sysConfig.getWechatWebPartner());
        paramMap.put("nonce_str", identities.uuid2());
        paramMap.put("out_trade_no", tradeNo);
        paramMap.put("out_refund_no", outRefundNo);
        paramMap.put("total_fee",String.valueOf(new BigDecimal(realPrice).multiply(new BigDecimal(100)).intValue()));
        paramMap.put("refund_fee",String.valueOf(new BigDecimal(refundPrice).multiply(new BigDecimal(100)).intValue()));
        paramMap.put("op_user_id",sysConfig.getWechatWebPartner());
        if("REFUND_SOURCE_UNSETTLED_FUNDS".equals(refundAccount) || "REFUND_SOURCE_RECHARGE_FUNDS".equals(refundAccount)){
            paramMap.put("refund_account", refundAccount);
        }
        String sign = WeChatTool.wxSign(paramMap, sysConfig.getWechatAppKey());
        paramMap.put("sign", sign);
        String xml = WeChatTool.getWxXml(paramMap);
        logger.info("微信公众号 查询退款请求参数：" + xml);
        String result = WeChatHttpClient.sendMsg(xml,sysConfig.getWechatWebPartner(),this.getClass().getClassLoader().getResource(sysConfig.getWechatWebPartner()+".p12").getPath());
        logger.info("微信公众号 查询退款返回结果：" + result);
        Map<String, String> resultMap = XmlUtil.doXMLParse(new String(result));
        Map map = Maps.newHashMap();
        if("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
            map.put("result",true);
            map.put("out_refund_no",resultMap.get("out_refund_no"));
            map.put("out_trade_no",resultMap.get("out_trade_no"));
            map.put("transaction_id",resultMap.get("transaction_id"));
            map.put("refund_fee",resultMap.get("refund_fee"));
            map.put("refund_channel",resultMap.get("refund_channel"));//ORIGINAL—原路退款 BALANCE—退回到余额
            map.put("trade_state",resultMap.get("trade_state"));
        }else{
            map.put("result",false);
            map.put("errorMsg","微信-订单退款-订单号:"+tradeNo+
                    "RETURN_CODE:"+resultMap.get("return_code")+
                    "RETURN_MSG:"+resultMap.get("return_msg"));
            if("SUCCESS".equals(resultMap.get("return_code"))){
                map.put("errorMsg","微信-订单退款-订单号:"+tradeNo+
                        "RETURN_CODE:"+resultMap.get("return_code")+
                        "RETURN_MSG:"+resultMap.get("return_msg")+
                        "ERR_CODE:"+resultMap.get("err_code")+
                        "ERR_CODE_DES:"+resultMap.get("err_code_des"));
            }
        }
        return map;
    }

}
